﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CarbonExchange.AmeeQuery;
using CarbonExchange.Dal;

namespace CarbonExchange.Bll
{
    public class EmailActivationCodeFactory : FactoryBase<EmailActivationCode>
    {
        public EmailActivationCodeFactory() : base() { }

        public EmailActivationCodeFactory(IAmeeCommand ameeCommand) : base(ameeCommand) { }

        public EmailActivationCodeFactory(Context dalContext) : base(dalContext) { }

        public EmailActivationCodeFactory(IAmeeCommand ameeCommand, Context dalContext) : base(ameeCommand, dalContext) { }

        protected override void MarkItemForDeletion(EmailActivationCode item)
        {
            if (item.Id > 0)
            {
                Dal.EmailActivationCode dataItem = item.Convert(DalContext);
                dataItem.Deleted = true;
            }
        }

        protected override void Validate(IQueryable<EmailActivationCode> items, CarbonExchange.Bll.Exceptions.ValidationException exp)
        {
            items.Validate(exp, DalContext);
        }

        protected override void PopulateDataChanges(EmailActivationCode item, object dataItem)
        {
            var tmp = dataItem as Dal.EmailActivationCode;
            if (item.Id == 0)
            {
                item.Id = tmp.Id;
                item.Created = tmp.Created.ToLocalTime();
            }
        }

        protected override object GetDataItemForUpdate(EmailActivationCode item)
        {
            return item.Convert(DalContext);
        }

        private IQueryable<Dal.EmailActivationCode> GetSelection()
        {
            return DalContext.EmailActivationCodes.Where(x => !x.Deleted);
        }

        public EmailActivationCode GetById(int id)
        {
            return GetSelection().Where(x => x.Id == id).SingleOrDefault().Convert();
        }

        public EmailActivationCode GetByCode(string code, int siteId)
        {
            return GetSelection().Where(x => x.Code == code).Join(DalContext.Users, x => x.UserId, y => y.Id, (x, y) => new {Code = x, User = y}).Where(x => x.User.SiteId == siteId).Select(x => x.Code).SingleOrDefault().Convert();
        }

        public IQueryable<EmailActivationCode> GetAllByUserId(int userId)
        {
            return GetSelection().Where(x => x.UserId == userId).Convert();
        }

    }

    public static class EmailActivationCodeConverter
    {

        public static IQueryable<EmailActivationCode> Convert(this IQueryable<Dal.EmailActivationCode> source)
        {
            return source.Select(x => ConvertItem(x));
        }

        public static EmailActivationCode Convert(this Dal.EmailActivationCode source)
        {
            return ConvertItem(source);
        }

        private static EmailActivationCode ConvertItem(Dal.EmailActivationCode item)
        {
            if (item != null)
            {
                return new EmailActivationCode()
                {
                    Id = item.Id,
                    Activated = item.Activated,
                    Code = item.Code,
                    Created = DateTime.SpecifyKind(item.Created, DateTimeKind.Utc).ToLocalTime(),
                    EmailAddress = item.EmailAddress,
                    UserId = item.UserId
                };
            }
            else
            {
                return null;
            }
        }

        internal static Dal.EmailActivationCode Convert(this EmailActivationCode item, Dal.Context context)
        {
            Dal.EmailActivationCode dbItem = null;
            if (item.Id > 0)
            {
                dbItem = context.EmailActivationCodes.Where(x => x.Id == item.Id).Single();
            }
            else
            {
                dbItem = new Dal.EmailActivationCode();
                context.EmailActivationCodes.InsertOnSubmit(dbItem);
                dbItem.Created = DateTime.Now.ToUniversalTime();
                dbItem.EmailAddress = item.EmailAddress;
                dbItem.UserId = item.UserId;
                dbItem.Code = item.Code;
            }

            dbItem.Activated = item.Activated;
            return dbItem;
        }

        internal static void Validate(this IQueryable<EmailActivationCode> source, Exceptions.ValidationException e, Dal.Context context)
        {
            Dictionary<int, List<EmailRestriction>> emailRestrictions = new Dictionary<int, List<EmailRestriction>>();
            foreach (EmailActivationCode item in source)
            {
                item.Validate(e, context);
            }
        }

        internal static void Validate(this EmailActivationCode source, Exceptions.ValidationException e, Dal.Context context)
        {
            if (string.IsNullOrEmpty(source.Code))
            {
                e.Add("Email Activation Code Must Be Set");
            }
            if (string.IsNullOrEmpty(source.EmailAddress))
            {
                e.Add("Email Activation EmailAddress Must Be Set");
            }
            if (source.UserId <= 0)
            {
                e.Add("Email Activation User Id Must Be Set");
            }
            //if new then check site email restrictions
            if (!(source.Id > 0))
            {
                EmailRestrictionFactory factory = new EmailRestrictionFactory(context);
                IQueryable<EmailRestriction> emailRestrictions = null;
                if(source.UserId == 0 && source.User == null)
                {
                    e.Add("User Id or User must be set when createing a new Email Activation Code");
                }
                else if (source.UserId == 0 && source.User != null && source.User.SiteId != null)
                {
                    emailRestrictions = factory.GetAllBySiteId(source.User.SiteId.Value);
                }
                else if (source.UserId != 0)
                {
                    emailRestrictions = factory.GetAllByUserId(source.UserId);
                }

                if (emailRestrictions != null)
                {
                    if (!factory.ValidateEmail(source.EmailAddress, emailRestrictions))
                    {
                        e.Add(string.Format("Email Address '{0}' did not match any of the restrictions", source.EmailAddress));
                    }
                }
                
            }
        }
    }
}
